/*********************************************************************************
  *Copyright(C),2015-2020, 
  *TUYA 
  *www.tuya.comm
  *FileName:    tuya_ipc_media_demo
**********************************************************************************/
#include <stdio.h>
#include <string.h>
#include <pthread.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/statfs.h>
#include "tuya_ipc_common_demo.h"
#include "tuya_ipc_api.h"
#include "tuya_ipc_stream_storage.h"
#include "tuya_ipc_cloud_storage.h"
#include "tuya_ipc_media_demo.h"
#include "tuya_g711_utils.h"
#include "tuya_ipc_media.h"
#include "tuya_ipc_dp_handler.h"

#define DEF_TAG         "TuyaIpc"

typedef enum
{
    TUYA_SDK_VIDEO_MAIN = 0,
    TUYA_SDK_VIDEO_SUB,
    TUYA_SDK_VIDEO_MAX,
}ETuyaSdkVideoChn;

extern CHAR_T s_raw_path[128];

void *thread_live_audio(void *arg)
{
    DEF_COM_SET_THREAD_NAME("Audio_Live",g_ComThread_Num);

    int ret;
    MEDIA_FRAME_S pcm_frame = {0};
    pcm_frame.type = E_AUDIO_FRAME;
    StSdkAudioInfo info;
    Com_u8 enc_buf[DEF_SDK_MIC_SIZE];

    Ring_Buffer_User_Handle_S a_handle = tuya_ipc_ring_buffer_open(0, 0, E_IPC_STREAM_AUDIO_MAIN, E_RBUF_WRITE);
    if(a_handle == NULL)
    {
        PRT_ERR(DEF_TAG,"live audio error\n");
        pthread_exit(0);
    }

    while(g_ComThread_Running)
    {
        ret = Ext_SdkMediaCom_GetMicData(&info);
        if (ret != DEF_COM_SUCCESS)
        {
            continue;
        }

        memset(enc_buf,0,sizeof(enc_buf));
        tuya_g711_encode(TUYA_G711_A_LAW,(unsigned short *)info.buf,info.size,enc_buf,&pcm_frame.size);
        pcm_frame.p_buf = enc_buf;
        pcm_frame.pts = info.pts;
        TUYA_APP_Put_Frame(a_handle,&pcm_frame);
        Ext_SdkMediaCom_ReleaseMicData();
    }

    DEF_COM_EXIT_THREAD(g_ComThread_Num);
}

void *thread_live_mainvideo(void *arg)
{
    DEF_COM_SET_THREAD_NAME("Video_Live",g_ComThread_Num);
    Com_s32 ret;
    unsigned long long int pts = 0;
    Com_u64 last_ts = 0;
    StSdkVideoInfo info;
    MEDIA_FRAME_S h264_frame;
    Ring_Buffer_User_Handle_S v_handle;

    memset(&v_handle, 0 ,sizeof(v_handle));
    v_handle = tuya_ipc_ring_buffer_open(0, 0, TUYA_SDK_VIDEO_MAIN, E_RBUF_WRITE);
    if (v_handle == NULL)
    {
        PRT_ERR(DEF_TAG, "m_v_handle = NULL\n");
        goto m_video_exit;
    }

    while(g_ComThread_Running)
    {
        ret = Ext_SdkMediaCom_GetVideoData(TUYA_SDK_VIDEO_MAIN, &info);
        if (ret != DEF_COM_SUCCESS)
        {
            continue;
        }

        if (Ext_SdkMediaCom_GetSleepMode() == DEF_COM_TRUE)
        {
            Ext_SdkMediaCom_ReleaseVideoData(TUYA_SDK_VIDEO_MAIN);
            usleep(10 * 1000);
            continue;
        }

        memset(&h264_frame, 0, sizeof(h264_frame));

        if (info.type == SDK_FRAME_TYPE_I)
        {
            h264_frame.type = E_VIDEO_I_FRAME;
        }
        else
        {
            h264_frame.type = E_VIDEO_PB_FRAME;
        }

        h264_frame.size = info.size;
        h264_frame.p_buf = info.buf;

        pts = (last_ts == 0) ? 0 : (pts + (info.pts - last_ts) * 1000);
        h264_frame.pts = pts;
        last_ts = info.pts;
        TUYA_APP_Put_Frame(v_handle, &h264_frame);
        Ext_SdkMediaCom_ReleaseVideoData(TUYA_SDK_VIDEO_MAIN);
    }

m_video_exit:
    DEF_COM_EXIT_THREAD(g_ComThread_Num);
}

void *thread_live_subvideo(void *arg)
{
    DEF_COM_SET_THREAD_NAME("Video_Live",g_ComThread_Num);
    Com_s32 ret;
    unsigned long long int pts = 0;
    Com_u64 last_ts = 0;
    StSdkVideoInfo info;
    MEDIA_FRAME_S h264_frame;
    Ring_Buffer_User_Handle_S v_handle;

    memset(&v_handle, 0 ,sizeof(v_handle));
    v_handle = tuya_ipc_ring_buffer_open(0, 0, TUYA_SDK_VIDEO_SUB, E_RBUF_WRITE);
    if (v_handle == NULL)
    {
        PRT_ERR(DEF_TAG, "s_v_handle = NULL\n");
        goto s_video_exit;
    }

    while(g_ComThread_Running)
    {

#if CMAKE_NONSUPPORT_GET_YUV && CMAKE_SUPPORT_QRCODE
        if (g_ComVideo_SubBuff_Flag == 0)
        {
            usleep(10 * 1000);
            continue;
        }
#endif

        ret = Ext_SdkMediaCom_GetVideoData(TUYA_SDK_VIDEO_SUB, &info);
        if (ret != DEF_COM_SUCCESS)
        {
            continue;
        }

        if (Ext_SdkMediaCom_GetSleepMode() == DEF_COM_TRUE)
        {
            Ext_SdkMediaCom_ReleaseVideoData(TUYA_SDK_VIDEO_SUB);
            usleep(10 * 1000);
            continue;
        }

        memset(&h264_frame, 0, sizeof(h264_frame));

        if (info.type == SDK_FRAME_TYPE_I)
        {
            h264_frame.type = E_VIDEO_I_FRAME;
        }
        else
        {
            h264_frame.type = E_VIDEO_PB_FRAME;
        }

        h264_frame.size = info.size;
        h264_frame.p_buf = info.buf;

        pts = (last_ts == 0) ? 0 : (pts + (info.pts - last_ts) * 1000);
        h264_frame.pts = pts;
        last_ts = info.pts;
        TUYA_APP_Put_Frame(v_handle, &h264_frame);
        Ext_SdkMediaCom_ReleaseVideoData(TUYA_SDK_VIDEO_SUB);
    }

s_video_exit:
    DEF_COM_EXIT_THREAD(g_ComThread_Num);
}

/*
---------------------------------------------------------------------------------
code related RingBuffer
---------------------------------------------------------------------------------
*/
OPERATE_RET TUYA_APP_Init_Ring_Buffer(VOID)
{
    return OPRT_OK;
}

OPERATE_RET TUYA_APP_Put_Frame(Ring_Buffer_User_Handle_S handle, IN CONST MEDIA_FRAME_S *p_frame)
{
    PR_TRACE("Put Frame. type:%d size:%u pts:%llu ts:%llu\n", p_frame->type,
             p_frame->size, p_frame->pts, p_frame->timestamp);

    OPERATE_RET ret = tuya_ipc_ring_buffer_append_data(handle,p_frame->p_buf, p_frame->size,p_frame->type,p_frame->pts);
    if(ret != OPRT_OK)
    {
        PR_ERR("Put Frame Fail.%d  type:%d size:%u pts:%llu ts:%llu",ret,
                p_frame->type, p_frame->size, p_frame->pts, p_frame->timestamp);
    }
    return ret;
}

#if 0
OPERATE_RET TUYA_APP_Get_Frame_Backwards(IN CONST IPC_STREAM_E channel,
                                         IN CONST USER_INDEX_E user_index,
                                         IN CONST UINT_T backward_frame_num,
                                         INOUT MEDIA_FRAME_S *p_frame)
{
    if(p_frame == NULL)
    {
        PR_ERR("input is null");
        return OPRT_INVALID_PARM;
    }

    Ring_Buffer_Node_S *node;
    if(channel == E_IPC_STREAM_VIDEO_MAIN || channel == E_IPC_STREAM_VIDEO_SUB)
        node = tuya_ipc_ring_buffer_get_pre_video_frame(channel,user_index,backward_frame_num);
    else
        node = tuya_ipc_ring_buffer_get_pre_audio_frame(channel,user_index,backward_frame_num);
    if(node != NULL)
    {
        p_frame->p_buf = node->rawData;
        p_frame->size = node->size;
        p_frame->timestamp = node->timestamp;
        p_frame->type = node->type;
        p_frame->pts = node->pts;
        return OPRT_OK;
    }
    else
    {
        PR_ERR("Fail to re-locate for user %d backward %d frames, channel %d",user_index,backward_frame_num,channel);
        return OPRT_COM_ERROR;
    }
}

OPERATE_RET TUYA_APP_Get_Frame(IN CONST IPC_STREAM_E channel, IN CONST USER_INDEX_E user_index, IN CONST BOOL_T isRetry, IN CONST BOOL_T ifBlock, INOUT MEDIA_FRAME_S *p_frame)
{
    if(p_frame == NULL)
    {
        PR_ERR("input is null");
        return OPRT_INVALID_PARM;
    }
    PR_TRACE("Get Frame Called. channel:%d user:%d retry:%d", channel, user_index, isRetry);

    Ring_Buffer_Node_S *node = NULL;
    while(node == NULL)
    {
        if(channel == E_IPC_STREAM_VIDEO_MAIN || channel == E_IPC_STREAM_VIDEO_SUB)
        {
            node = tuya_ipc_ring_buffer_get_video_frame(channel,user_index,isRetry);
        }
        else if(channel == E_IPC_STREAM_AUDIO_MAIN)
        {
            node = tuya_ipc_ring_buffer_get_audio_frame(channel,user_index,isRetry);
        }
        if(NULL == node)
        {
            if(ifBlock)
            {
                usleep(10*1000);
            }
            else
            {
                return OPRT_NO_MORE_DATA;
            }
        }
    }
    p_frame->p_buf = node->rawData;
    p_frame->size = node->size;
    p_frame->timestamp = node->timestamp;
    p_frame->type = node->type;
    p_frame->pts = node->pts;

    PR_TRACE("Get Frame Success. channel:%d user:%d retry:%d size:%u ts:%ull type:%d pts:%llu",
             channel, user_index, isRetry, p_frame->size, p_frame->timestamp, p_frame->type, p_frame->pts);
    return OPRT_OK;
}
#endif
/*
---------------------------------------------------------------------------------
---------------------------------------------------------------------------------
*/

/*
---------------------------------------------------------------------------------
code related EchoShow
---------------------------------------------------------------------------------
*/
#if ENABLE_ECHO_SHOW == 1

INT_T TUYA_APP_Echoshow_Start(PVOID_T context, PVOID_T priv_data)
{
    printf("echoshow start...\n");

    return 0;
}

INT_T TUYA_APP_Echoshow_Stop(PVOID_T context, PVOID_T priv_data)
{
    printf("echoshow stop...\n");

    return 0;
}

INT_T TUYA_APP_Chromecast_Start(PVOID_T context, PVOID_T priv_data)
{
    printf("chromecast start...\n");

    return 0;
}

INT_T TUYA_APP_Chromecast_Stop(PVOID_T context, PVOID_T priv_data)
{
    printf("chromecast stop...\n");

    return 0;
}

OPERATE_RET TUYA_APP_Enable_EchoShow_Chromecast(VOID)
{
#if 0
    STATIC BOOL_T s_echoshow_inited = FALSE;
    if(s_echoshow_inited == TRUE)
    {
        PR_DEBUG("The EchoShow Is Already Inited");
        return OPRT_OK;
    }

    PR_DEBUG("Init EchoShow");

    TUYA_ECHOSHOW_PARAM_S es_param = {0};

    es_param.pminfo = &s_media_info;
    es_param.cbk.pcontext = NULL;
    es_param.cbk.start = TUYA_APP_Echoshow_Start;
    es_param.cbk.stop = TUYA_APP_Echoshow_Stop;
    /*Channel settings according to requirements*/
    es_param.vchannel = 1;
    es_param.mode = TUYA_ECHOSHOW_MODE_ECHOSHOW;

    tuya_ipc_echoshow_init(&es_param);

    TUYA_CHROMECAST_PARAM_S param = {0};

    param.pminfo = &s_media_info;
    /*Channel settings according to requirements*/
    param.audio_channel = E_IPC_STREAM_AUDIO_MAIN_2RD;
    param.video_channel = E_IPC_STREAM_VIDEO_SUB;
    param.src = TUYA_STREAM_SOURCE_RINGBUFFER;
    param.mode = TUYA_STREAM_TRANSMIT_MODE_ASYNC;
    param.cbk.pcontext = NULL;
    param.cbk.start = TUYA_APP_Chromecast_Start;
    param.cbk.stop = TUYA_APP_Chromecast_Stop;
    param.cbk.get_frame = NULL;

    tuya_ipc_chromecast_init(&param);

    s_echoshow_inited = TRUE;
#endif
    return OPRT_OK;
}
#endif
/*
---------------------------------------------------------------------------------

---------------------------------------------------------------------------------
*/


